﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections.Specialized;
using Extjs_ReGSharp.Criteria.Factory;
using Extjs_ReGSharp.Criteria;

namespace Extjs_ReGSharp.InputParsing
{
	internal class CriteriaExtractor<T>
	{
		#region Consts

		private const string FilterFieldName = "filter[{0}][field]";
		private const string FilterFieldType = "filter[{0}][data][type]";
		private const string FilterFieldComparison = "filter[{0}][data][comparison]";
		private const string FilterFieldValue = "filter[{0}][data][value]";

		#endregion

		#region Data Memebers

		private NameValueCollection m_InputParameters;

		#endregion

		#region Private Methods

		private CriteriaDefinitionDTO ExtractFilter(string fieldNameHeader, 
			string fieldTypeHeader, 
			string fieldComparisonHeader, 
			string fieldValueHeader)
		{
			string fieldName = m_InputParameters[fieldNameHeader];
			string fieldValue = m_InputParameters[fieldValueHeader];
			string fieldComparison = m_InputParameters[fieldComparisonHeader];
			string fieldType = m_InputParameters[fieldTypeHeader];

			CriteriaDefinitionDTO result = new CriteriaDefinitionDTO() { FieldName = fieldName, FieldType = fieldType, FieldComparison = fieldComparison, Value = fieldValue };

			return result;
		}

		private List<CriteriaDefinitionDTO> ExtractCriteriaDefinitionsFromInput()
		{
			List<CriteriaDefinitionDTO> criteriaDefinitions = new List<CriteriaDefinitionDTO>();

			int i = 0;
			bool hasMoreFilters = true;

			while (hasMoreFilters)
			{
				string fieldNameHeader = string.Format(FilterFieldName, i);
				string fieldTypeHeader = string.Format(FilterFieldType, i);
				string fieldComparisonHeader = string.Format(FilterFieldComparison, i);
				string fieldValueHeader = string.Format(FilterFieldValue, i);

				i++;

				if (m_InputParameters.AllKeys.Contains(fieldNameHeader))
				{
					CriteriaDefinitionDTO criteriaDefinition = ExtractFilter(fieldNameHeader, 
						fieldTypeHeader, 
						fieldComparisonHeader,
						fieldValueHeader);

					criteriaDefinitions.Add(criteriaDefinition);
				}
				else
				{
					hasMoreFilters = false;
				}
			}

			return criteriaDefinitions;
		}

		private static Filter<T> CreateFilterFromCriteriaDefinitions(List<CriteriaDefinitionDTO> criteriaDefinitions)
		{
			ICriteriaFactory factory = new CriteriaFactory();

			AndCriteria<T> mainCriteria = new AndCriteria<T>();

			foreach (CriteriaDefinitionDTO criteriaDefinition in criteriaDefinitions)
			{
				ICriteria<T> criteria = factory.CreateCriteria<T>(criteriaDefinition);

				mainCriteria.AddCriteria(criteria);
			}

			Filter<T> result = new Filter<T>(mainCriteria);

			return result;
		}

		#endregion

		#region Constructor

		internal CriteriaExtractor(NameValueCollection inputParameters)
		{
			m_InputParameters = inputParameters;
		}

		#endregion

		#region Public Methods

		public Filter<T> ExtractFilter()
		{
			List<CriteriaDefinitionDTO> criteriaDefinitions = ExtractCriteriaDefinitionsFromInput();

			Filter<T> result = CreateFilterFromCriteriaDefinitions(criteriaDefinitions);

			return result;
		}

		#endregion
	}
}
